package system

import (
	"MoSkeleton/config/consts"
	"MoSkeleton/framework/core/models"
	"MoSkeleton/models/base"
	"gorm.io/gorm"
	"strings"
)

type SysDept struct {
	models.MoModel
	ParentId  uint64  `gorm:"column:parent_id;type:BIGINT;" json:"parentId,string"`
	Ancestors string  `gorm:"column:ancestors;type:VARCHAR(50);"`
	DeptName  string  `gorm:"column:dept_name;type:VARCHAR(30);"`
	OrderNum  int32   `gorm:"column:order_num;type:INT;"`
	Leader    string  `gorm:"column:leader;type:VARCHAR(20);"`
	Phone     string  `gorm:"column:phone;type:VARCHAR(11);"`
	Email     string  `gorm:"column:email;type:VARCHAR(50);"`
	Status    *string `gorm:"column:status;type:CHAR(1);"`
	DelFlag   *string `gorm:"column:del_flag;type:CHAR(1);"`
	CreatedBy string  `gorm:"column:created_by;type:VARCHAR(32);"`
	UpdatedBy string  `gorm:"column:updated_by;type:VARCHAR(32);"`
}

func (p *SysDept) TableName() string {
	return "sys_dept"
}

/*
select count(*) from sys_dept where status = 0 and del_flag = '0' and find_in_set(#{deptId}, ancestors)
*/
func (d *SysDept) GetNormalChildrenDeptCount(tx *gorm.DB) (int64, error) {
	var count int64
	if err := base.GetModelDB(tx).Model(d).Where("status = ? and del_flag = ? and find_in_set(?, ancestors)", 0, 0, d.ID).Count(&count).Error; err != nil {
		return 0, err
	}
	return count, nil
}

/*
update sys_dept set ancestors =

	<foreach collection="depts" item="item" index="index"
	    separator=" " open="case dept_id" close="end">
	    when #{item.deptId} then #{item.ancestors}
	</foreach>
	where dept_id in
	<foreach collection="depts" item="item" index="index"
	    separator="," open="(" close=")">
	    #{item.deptId}
	</foreach>
*/
func (d *SysDept) UpdateChildrenAncestors(tx *gorm.DB, newAncestors, oldAncestors string) error {
	children, err := d.getChildrenDepts(tx)
	if err != nil {
		return err
	}
	childrenIds := make([]uint64, 0)
	for _, child := range children {
		child.Ancestors = strings.Replace(child.Ancestors, oldAncestors, newAncestors, 1)
		childrenIds = append(childrenIds, child.ID)
	}
	return base.GetModelDB(tx).Model(d).Where("id in (?)", childrenIds).Update("ancestors", gorm.Expr("REPLACE(ancestors, ?, ?)", oldAncestors, newAncestors)).Error
}

/*
select * from sys_dept where find_in_set(#{deptId}, ancestors)
*/
func (d *SysDept) getChildrenDepts(tx *gorm.DB) ([]*SysDept, error) {
	var depts []*SysDept
	if err := base.GetModelDB(tx).Model(d).Where("find_in_set(?, ancestors)", d.ID).Find(&depts).Error; err != nil {
		return nil, err
	}
	return depts, nil
}
func (d *SysDept) HasChildrenDept() (bool, error) {
	var count int64
	if err := base.GetModelDB(nil).Model(d).Where("parent_id = ?", d.ID).Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}

/*
如果该部门是启用状态，则启用该部门的所有上级部门

update sys_dept set status = '0' where dept_id in

		    <foreach collection="array" item="deptId" open="(" separator="," close=")">
	       	#{deptId}
	       </foreach>
*/
func (d *SysDept) UpdateParentDeptStatusNormal(tx *gorm.DB) error {
	parentIds := strings.Split(d.Ancestors, ",")
	return base.GetModelDB(tx).Model(&SysDept{}).Where("id in (?)", parentIds).Update("status", consts.U_NORMAL).Error
}

/*
select d.id

			from sys_dept d
	            left join sys_role_dept rd on d.id = rd.dept_id
	        where rd.role_id = #{roleId}
	            <if test="deptCheckStrictly">
	              and d.id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.id = rd.dept_id and rd.role_id = #{roleId})
	            </if>
			order by d.parent_id, d.order_num
*/
func (d *SysDept) GetDeptIdListByRoleId(tx *gorm.DB, roleId uint64, isDeptCheckStrictly bool) ([]uint64, error) {
	db := base.GetModelDB(tx).Select("d.id").Table("sys_dept d")
	db.Joins("left join sys_role_dept rd on d.id = rd.dept_id")
	db.Where("rd.role_id = ?", roleId)
	if isDeptCheckStrictly {
		db.Where("d.id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.id = rd.dept_id and rd.role_id = ?)", roleId)
	}
	db.Order("d.parent_id, d.order_num")
	result := make([]uint64, 0)
	return result, db.Find(&result).Error
}

/*
select p.post_id

	        from sys_post p
		        left join sys_user_post up on up.post_id = p.post_id
		        left join sys_user u on u.user_id = up.user_id
		    where u.user_id = #{userId}
*/
func (d *SysDept) GetDeptIdsByUserId(userId uint64) ([]uint64, error) {
	var deptIds []uint64
	db := base.GetModelDB(nil).Model(d).Select("p.id").Table("sys_post p")
	db.Joins("left join sys_user_post up on up.post_id = p.id")
	db.Joins("left join sys_user u on u.id = up.user_id")
	db.Where("u.id = ?", userId)
	if err := db.Find(&deptIds).Error; err != nil {
		return nil, err
	}
	return deptIds, nil
}
